package com.hundsun.aitest.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hundsun.aitest.model.ai.ChatRequest;
import com.hundsun.aitest.model.ai.Message;
import com.hundsun.aitest.service.LargeModelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
public class ExcelUtils {


    /**
     * 读取Excel文件内容。
     *
     * @param filePath 文件路径
     * @return 二维列表，表示Excel文件的数据
     * @throws IOException 如果文件读取失败
     */
    public static List<List<String>> readXlsxFile(String filePath) throws IOException {
        List<List<String>> data = new ArrayList<>();
        try (FileInputStream fis = new FileInputStream(new File(filePath))) {
            Workbook workbook = new XSSFWorkbook(fis);
            Sheet sheet = workbook.getSheetAt(0); // 假设我们只处理第一个工作表
            int lastRowNum = sheet.getLastRowNum();

            // 记录合并单元格的范围
            List<CellRangeAddress> mergedRegions = new ArrayList<>();
            for (CellRangeAddress range : sheet.getMergedRegions()) {
                mergedRegions.add(range);
            }

            for (int i = sheet.getFirstRowNum(); i <= lastRowNum; i++) {
                Row row = sheet.getRow(i);
                List<String> rowData = new ArrayList<>();
                int lastColumnNum = row.getLastCellNum();

                for (int j = 0; j < lastColumnNum; j++) {
                    String cellValue = getCellValue(row, j, mergedRegions);
                    rowData.add(cellValue);
                }
                data.add(rowData);
            }
        }

        return data;
    }

    /**
     * 获取单元格的值，考虑到合并单元格的情况。
     *
     * @param row          当前行
     * @param columnIndex  列索引
     * @param mergedRegions 合并单元格的列表
     * @return 单元格的值
     */
    private static String getCellValue(Row row, int columnIndex, List<CellRangeAddress> mergedRegions) {
        Cell cell = row.getCell(columnIndex, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
        if (cell != null) {
            switch (cell.getCellType()) {
                case STRING:
                    return cell.getStringCellValue();
                case NUMERIC:
                    return String.valueOf(cell.getNumericCellValue());
                case BOOLEAN:
                    return String.valueOf(cell.getBooleanCellValue());
                default:
                    return "";
            }
        }

        // 检查是否为合并单元格
        for (CellRangeAddress range : mergedRegions) {
            if (range.isInRange(row.getRowNum(), columnIndex)) {
                // 找到合并单元格的起始位置
                int firstColumn = range.getFirstColumn();
                cell = row.getCell(firstColumn, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                if (cell != null) {
                    switch (cell.getCellType()) {
                        case STRING:
                            return cell.getStringCellValue();
                        case NUMERIC:
                            return String.valueOf(cell.getNumericCellValue());
                        case BOOLEAN:
                            return String.valueOf(cell.getBooleanCellValue());
                        default:
                            return "";
                    }
                }
            }
        }
        return ""; // 如果没有找到对应的单元格，则返回空字符串
    }

    /**
     * 更新指定单元格的值。
     *
     * @param filePath 文件路径
     * @param rowIndex 行索引
     * @param columnIndex 列索引
     * @param value 新值
     * @throws IOException 如果文件读取或写入失败
     */
    public static void updateXlsxFile(String filePath, int rowIndex, int columnIndex, String value) throws IOException {
        try (FileInputStream fis = new FileInputStream(new File(filePath))) {
            Workbook workbook = new XSSFWorkbook(fis);
            Sheet sheet = workbook.getSheetAt(0); // 假设我们只处理第一个工作表

            // 记录合并单元格的范围
            List<CellRangeAddress> mergedRegions = new ArrayList<>();
            for (CellRangeAddress range : sheet.getMergedRegions()) {
                mergedRegions.add(range);
            }

            Row row = sheet.getRow(rowIndex);
            if (row == null) {
                row = sheet.createRow(rowIndex);
            }
            Cell cell = row.getCell(columnIndex);
            if (cell == null) {
                cell = row.createCell(columnIndex);
            }

            // 检查是否为合并单元格的一部分
            for (CellRangeAddress range : mergedRegions) {
                if (range.isInRange(rowIndex, columnIndex)) {
                    // 如果是合并单元格的一部分，则更新起始单元格
                    int firstColumn = range.getFirstColumn();
                    int firstRow = range.getFirstRow();
                    cell = row.getCell(firstColumn, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                    if (cell == null) {
                        cell = row.createCell(firstColumn);
                    }
                    cell.setCellValue(value);
                    break; // 更新后跳出循环
                }
            }

            try (FileOutputStream fos = new FileOutputStream(filePath)) {
                workbook.write(fos);
            }
        }
    }


    /**
     * 更新Excel文件中的行，使用大模型接口查询结果。
     *
     * @param filePath 文件路径
     * @param columnIndexName 用例名称所在的列索引（从0开始）
     * @param columnIndexPrior 优先级所在的列索引
     * @param largeModelService 大模型接口
     * @throws IOException 如果文件读取或写入失败
     */
    public static void updateRowsWithModelResponse(String filePath, int columnIndexName, int columnPath, int columnIndexPrior, LargeModelService largeModelService) throws IOException {
        List<List<String>> data = readXlsxFile(filePath);
        log.info("excel读取结束");
        int batchSize = 20;
        int totalRows = data.size();
        int lastRowNum = data.size() - 1;

        // 分批次处理
        for (int i = 0; i <= lastRowNum; i += batchSize) {
            int end = Math.min(i + batchSize, totalRows);
            List<List<String>> batch = data.subList(i, end);

            // 构造请求并发送给大模型接口
            List<String> requests = constructRequests(batch, columnIndexName,columnPath,filePath,data);
            String prompt="给下面的用例列表，标注优先级P0~P3,P0优先级最高，结果按照json格式返回，直接给出结果，不要分析过程。\n" +
                    "P0~P3标准：\n" +
                    "P0: 冒烟级用例(场景发生概率极高，执行失败会导致流程阻塞、系统崩溃、重大任务不能正常进行等。),参考占比：5%-10%\n" +
                    "P1：高级别用例（场景发生概率高，执行失败会导致系统常用功能无法完整使用，且没有办法避免冲突。或发生概率低，执行失败会导致流程阻断。），参考占比：15%-25%\n" +
                    "P2：中级别用例（场景发生概率中，执行失败会导致系统次要功能丧失，不太严重，可通过变通手段解决。验证程序是否好用，更全面的验证业务开展的场景）参考占比：55%-65%\n" +
                    "P3：低级别用例（场景发生概率低，执行失败用户可以使用，但使用感不好。验证程序的易用性，体验感）参考占比：5%-10%\n" +
                    "\n" +
                    "用例列表：\n"
                    + String.join("\n",requests)
                    + "\n" +
                    "返回格式（标准的json格式）：\n" +
                    "{\n" +
                    "   \"0:xxxx\":\"P0\",\n" +
                    "   \"1:xxxx\":\"P1\"\n" +
                    "}";
            ChatRequest chatRequest=new ChatRequest();

            chatRequest.setMessages(Arrays.asList(new Message("user", prompt)));
            log.info("第{}次开始调用大模型",i);
            String aiResult = largeModelService.sendRequest(chatRequest);

            String jsonString = largeModelService.parseResponse(aiResult);
            log.info("第{}次结束调用大模型,模型返回结果：\n{}",i,jsonString);
            jsonString=JsonContentExtractor.extractJsonContent(jsonString);
            // 解析 AI 结果
            List<String> responses = parseAiResult(jsonString);

            // 确保 responses 和 batch 的大小相同
            while (responses.size() < batch.size()) {
                responses.add(""); // 添加默认值或空字符串
            }

            // 更新Excel文件中的行,跟新
            log.info("第{}次开始写入excel结果",i);
            updateRows(filePath, batch, columnIndexPrior, responses);
            log.info("第{}次写入excel结束",i);
        }
    }

    /**
     * 解析AI结果并转换为响应列表。
     *
     * @param aiResult 从大模型服务返回的JSON字符串
     * @return 转换后的响应列表
     */
    public static List<String> parseAiResult(String aiResult) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<String> responses = new ArrayList<>();

        try {
            // 将 JSON 字符串转换为 Map 对象
            Map<String, String> parsedResponses = objectMapper.readValue(aiResult, Map.class);

            // 遍历 Map 并转换为响应格式
            for (Map.Entry<String, String> entry : parsedResponses.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                // 假设 key 的格式为 "0:xxxx" 或 "1:xxxx"
                // 我们需要从中提取出行号
                String[] parts = key.split(":");
                if (parts.length == 2) {
                    String rowNumber = parts[0]; // 这里是行号
                    responses.add(value); // 直接添加优先级值到 responses 列表
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Error parsing AI result", e);
        }

        return responses;
    }

    /**
     * 构造请求列表，每个请求包含行号和指定列的值。
     *
     * @param batch 批次数据
     * @param columnIndex 列索引
     * @return 请求列表
     */
    private static List<String> constructRequests(List<List<String>> batch, int columnIndex,int columnPath, String filePath,List<List<String>> data) {
        List<String> requests = new ArrayList<>();
        List<CellRangeAddress> mergedRegions = new ArrayList<>(); // 用于存储合并单元格的范围

        try (FileInputStream fis = new FileInputStream(new File(filePath))) {
            Workbook workbook = new XSSFWorkbook(fis);
            Sheet sheet = workbook.getSheetAt(0); // 假设我们只处理第一个工作表

            // 记录合并单元格的范围
            for (CellRangeAddress range : sheet.getMergedRegions()) {
                mergedRegions.add(range);
            }
        } catch (IOException e) {
            throw new RuntimeException("Error reading file", e);
        }

        for (int i = 0; i < batch.size(); i++) {
            List<String> row = batch.get(i);
            String rowNumber = String.valueOf(i); // 行号
            String columnValue = getColumnValue(row, columnIndex, mergedRegions, data);
            String pathValue = getColumnValue(row, columnPath, mergedRegions, data);
            String request = rowNumber + ": " + pathValue + "/" + columnValue;
            requests.add(request);
        }
        return requests;
    }

    /**
     * 获取指定列的值，考虑到合并单元格的情况。
     *
     * @param row 当前行数据
     * @param columnIndex 列索引
     * @param mergedRegions 合并单元格的列表
     * @return 单元格的值
     */
    private static String getColumnValue(List<String> row, int columnIndex, List<CellRangeAddress> mergedRegions,List<List<String>> data) {
        if (row.size() > columnIndex) {
            String value = row.get(columnIndex);
            if (!value.isEmpty()) {
                return value;
            }
        }

        // 检查是否为合并单元格的一部分
        for (CellRangeAddress range : mergedRegions) {
            if (range.isInRange(row.size(), columnIndex)) {
                // 如果是合并单元格的一部分，则使用起始单元格的值
                int firstColumn = range.getFirstColumn();
                int firstRow = range.getFirstRow();
                List<String> firstRowData = data.get(firstRow);
                return firstRowData.get(firstColumn);
            }
        }
        return ""; // 如果没有找到对应的单元格，则返回空字符串
    }

    /**
     * 更新Excel文件中的行。
     *
     * @param filePath 文件路径
     * @param batch 批次数据
     * @param columnIndex 列索引
     * @param responses 大模型接口的响应
     * @throws IOException 如果文件读取或写入失败
     */
    private static void updateRows(String filePath, List<List<String>> batch, int columnIndex, List<String> responses) throws IOException {
        try (FileInputStream fis = new FileInputStream(new File(filePath))) {
            Workbook workbook = new XSSFWorkbook(fis);
            Sheet sheet = workbook.getSheetAt(0); // 假设我们只处理第一个工作表

            for (int i = 0; i < batch.size(); i++) {
                Row excelRow = sheet.getRow(i); // 直接使用列表中的索引作为行号
                Cell cell = excelRow.getCell(columnIndex);
                if (cell == null) {
                    cell = excelRow.createCell(columnIndex);
                }
                cell.setCellValue(responses.get(i));
            }

            try (FileOutputStream fos = new FileOutputStream(filePath)) {
                workbook.write(fos);
            }
        }
    }

}